module decoder_2_4 (
    input wire [1:0] in,
    output reg [3:0] out
);
    always @ (*) begin
        case(in)
            2'b00:begin out = 4'b0001; end
            2'b01:begin out = 4'b0010; end
            2'b10:begin out = 4'b0100; end
            2'b11:begin out = 4'b1000; end
            default:begin
                out = 4'b0000;
            end
        endcase
    end
endmodule module decoder_3_8 (
    input wire [2:0] in,
    output reg [7:0] out
);
    always @ (*) begin
        case(in)
            3'b000:begin out = 8'b1; end
            3'b001:begin out = 8'b10; end
            3'b010:begin out = 8'b100; end
            3'b011:begin out = 8'b1000; end
            3'b100:begin out = 8'b10000; end
            3'b101:begin out = 8'b100000; end
            3'b110:begin out = 8'b1000000; end 
            3'b111:begin out = 8'b10000000; end
            default:begin
                out = 8'b0;
            end
        endcase
    end
endmodule module decoder_4_16(
    input wire [3:0] in,
    output reg [15:0] out
);
    always @ (*) begin
        case(in)
            4'd0:begin out = 16'b1; end
            4'd1:begin out = 16'b10; end
            4'd2:begin out = 16'b100; end
            4'd3:begin out = 16'b1000; end
            4'd4:begin out = 16'b10000; end
            4'd5:begin out = 16'b100000; end
            4'd6:begin out = 16'b1000000; end
            4'd7:begin out = 16'b10000000; end
            4'd8:begin out = 16'b100000000; end
            4'd9:begin out = 16'b1000000000; end
            4'd10:begin out = 16'b10000000000; end
            4'd11:begin out = 16'b100000000000; end
            4'd12:begin out = 16'b1000000000000; end
            4'd13:begin out = 16'b10000000000000; end
            4'd14:begin out = 16'b100000000000000; end
            4'd15:begin out = 16'b1000000000000000; end
            default:begin
                out = 16'b0;
            end
        endcase 
    end
endmodulemodule decoder_5_32 (
    input wire [4:0] in,
    output reg [31:0] out
);
    always @ (*) begin
        case(in)
            5'd00:begin out=32'b00000000000000000000000000000001; end
            5'd01:begin out=32'b00000000000000000000000000000010; end
            5'd02:begin out=32'b00000000000000000000000000000100; end
            5'd03:begin out=32'b00000000000000000000000000001000; end
            5'd04:begin out=32'b00000000000000000000000000010000; end
            5'd05:begin out=32'b00000000000000000000000000100000; end
            5'd06:begin out=32'b00000000000000000000000001000000; end
            5'd07:begin out=32'b00000000000000000000000010000000; end
            5'd08:begin out=32'b00000000000000000000000100000000; end
            5'd09:begin out=32'b00000000000000000000001000000000; end
            5'd10:begin out=32'b00000000000000000000010000000000; end
            5'd11:begin out=32'b00000000000000000000100000000000; end
            5'd12:begin out=32'b00000000000000000001000000000000; end
            5'd13:begin out=32'b00000000000000000010000000000000; end
            5'd14:begin out=32'b00000000000000000100000000000000; end
            5'd15:begin out=32'b00000000000000001000000000000000; end
            5'd16:begin out=32'b00000000000000010000000000000000; end
            5'd17:begin out=32'b00000000000000100000000000000000; end
            5'd18:begin out=32'b00000000000001000000000000000000; end
            5'd19:begin out=32'b00000000000010000000000000000000; end
            5'd20:begin out=32'b00000000000100000000000000000000; end
            5'd21:begin out=32'b00000000001000000000000000000000; end
            5'd22:begin out=32'b00000000010000000000000000000000; end
            5'd23:begin out=32'b00000000100000000000000000000000; end
            5'd24:begin out=32'b00000001000000000000000000000000; end
            5'd25:begin out=32'b00000010000000000000000000000000; end
            5'd26:begin out=32'b00000100000000000000000000000000; end
            5'd27:begin out=32'b00001000000000000000000000000000; end
            5'd28:begin out=32'b00010000000000000000000000000000; end
            5'd29:begin out=32'b00100000000000000000000000000000; end
            5'd30:begin out=32'b01000000000000000000000000000000; end
            5'd31:begin out=32'b10000000000000000000000000000000; end
            default:begin
                out=32'b0;
            end
        endcase
    end
endmodulemodule decoder_6_64 (
    input wire [5:0] in,
    output reg [63:0] out
);
    always @ (*) begin
        case(in)
            6'd00:begin out=64'b0000000000000000000000000000000000000000000000000000000000000001; end
            6'd01:begin out=64'b0000000000000000000000000000000000000000000000000000000000000010; end
            6'd02:begin out=64'b0000000000000000000000000000000000000000000000000000000000000100; end
            6'd03:begin out=64'b0000000000000000000000000000000000000000000000000000000000001000; end
            6'd04:begin out=64'b0000000000000000000000000000000000000000000000000000000000010000; end
            6'd05:begin out=64'b0000000000000000000000000000000000000000000000000000000000100000; end
            6'd06:begin out=64'b0000000000000000000000000000000000000000000000000000000001000000; end
            6'd07:begin out=64'b0000000000000000000000000000000000000000000000000000000010000000; end
            6'd08:begin out=64'b0000000000000000000000000000000000000000000000000000000100000000; end
            6'd09:begin out=64'b0000000000000000000000000000000000000000000000000000001000000000; end
            6'd10:begin out=64'b0000000000000000000000000000000000000000000000000000010000000000; end
            6'd11:begin out=64'b0000000000000000000000000000000000000000000000000000100000000000; end
            6'd12:begin out=64'b0000000000000000000000000000000000000000000000000001000000000000; end
            6'd13:begin out=64'b0000000000000000000000000000000000000000000000000010000000000000; end
            6'd14:begin out=64'b0000000000000000000000000000000000000000000000000100000000000000; end
            6'd15:begin out=64'b0000000000000000000000000000000000000000000000001000000000000000; end
            6'd16:begin out=64'b0000000000000000000000000000000000000000000000010000000000000000; end
            6'd17:begin out=64'b0000000000000000000000000000000000000000000000100000000000000000; end
            6'd18:begin out=64'b0000000000000000000000000000000000000000000001000000000000000000; end
            6'd19:begin out=64'b0000000000000000000000000000000000000000000010000000000000000000; end
            6'd20:begin out=64'b0000000000000000000000000000000000000000000100000000000000000000; end
            6'd21:begin out=64'b0000000000000000000000000000000000000000001000000000000000000000; end
            6'd22:begin out=64'b0000000000000000000000000000000000000000010000000000000000000000; end
            6'd23:begin out=64'b0000000000000000000000000000000000000000100000000000000000000000; end
            6'd24:begin out=64'b0000000000000000000000000000000000000001000000000000000000000000; end
            6'd25:begin out=64'b0000000000000000000000000000000000000010000000000000000000000000; end
            6'd26:begin out=64'b0000000000000000000000000000000000000100000000000000000000000000; end
            6'd27:begin out=64'b0000000000000000000000000000000000001000000000000000000000000000; end
            6'd28:begin out=64'b0000000000000000000000000000000000010000000000000000000000000000; end
            6'd29:begin out=64'b0000000000000000000000000000000000100000000000000000000000000000; end
            6'd30:begin out=64'b0000000000000000000000000000000001000000000000000000000000000000; end
            6'd31:begin out=64'b0000000000000000000000000000000010000000000000000000000000000000; end
            6'd32:begin out=64'b0000000000000000000000000000000100000000000000000000000000000000; end
            6'd33:begin out=64'b0000000000000000000000000000001000000000000000000000000000000000; end
            6'd34:begin out=64'b0000000000000000000000000000010000000000000000000000000000000000; end
            6'd35:begin out=64'b0000000000000000000000000000100000000000000000000000000000000000; end
            6'd36:begin out=64'b0000000000000000000000000001000000000000000000000000000000000000; end
            6'd37:begin out=64'b0000000000000000000000000010000000000000000000000000000000000000; end
            6'd38:begin out=64'b0000000000000000000000000100000000000000000000000000000000000000; end
            6'd39:begin out=64'b0000000000000000000000001000000000000000000000000000000000000000; end
            6'd40:begin out=64'b0000000000000000000000010000000000000000000000000000000000000000; end
            6'd41:begin out=64'b0000000000000000000000100000000000000000000000000000000000000000; end
            6'd42:begin out=64'b0000000000000000000001000000000000000000000000000000000000000000; end
            6'd43:begin out=64'b0000000000000000000010000000000000000000000000000000000000000000; end
            6'd44:begin out=64'b0000000000000000000100000000000000000000000000000000000000000000; end
            6'd45:begin out=64'b0000000000000000001000000000000000000000000000000000000000000000; end
            6'd46:begin out=64'b0000000000000000010000000000000000000000000000000000000000000000; end
            6'd47:begin out=64'b0000000000000000100000000000000000000000000000000000000000000000; end
            6'd48:begin out=64'b0000000000000001000000000000000000000000000000000000000000000000; end
            6'd49:begin out=64'b0000000000000010000000000000000000000000000000000000000000000000; end
            6'd50:begin out=64'b0000000000000100000000000000000000000000000000000000000000000000; end
            6'd51:begin out=64'b0000000000001000000000000000000000000000000000000000000000000000; end
            6'd52:begin out=64'b0000000000010000000000000000000000000000000000000000000000000000; end
            6'd53:begin out=64'b0000000000100000000000000000000000000000000000000000000000000000; end
            6'd54:begin out=64'b0000000001000000000000000000000000000000000000000000000000000000; end
            6'd55:begin out=64'b0000000010000000000000000000000000000000000000000000000000000000; end
            6'd56:begin out=64'b0000000100000000000000000000000000000000000000000000000000000000; end
            6'd57:begin out=64'b0000001000000000000000000000000000000000000000000000000000000000; end
            6'd58:begin out=64'b0000010000000000000000000000000000000000000000000000000000000000; end
            6'd59:begin out=64'b0000100000000000000000000000000000000000000000000000000000000000; end
            6'd60:begin out=64'b0001000000000000000000000000000000000000000000000000000000000000; end
            6'd61:begin out=64'b0010000000000000000000000000000000000000000000000000000000000000; end
            6'd62:begin out=64'b0100000000000000000000000000000000000000000000000000000000000000; end
            6'd63:begin out=64'b1000000000000000000000000000000000000000000000000000000000000000; end   
            default:begin
                out=64'b0;
            end
        endcase
    end

endmodule /* alu module: Archmetci login unit, combinational digital circuit
** input: 
** alu_op:      the control signal to decide which operations
** alu_src1:    the first operand 
** alu_src2:    the second operand 
** alu_result:  the archmetic result
*/
module alu(
    input wire [14:0] alu_op,
    input wire [63:0] alu_src1,
    input wire [63:0] alu_src2,
    output wire [63:0] alu_result
);

    wire op_and;
    wire op_or;
    wire op_xor;
    wire op_add;
    wire op_sub;
    wire op_slt;
    wire op_sltu;
    wire op_sll;
    wire op_srl;
    wire op_sra;
    wire op_addw;
    wire op_subw;
    wire op_sllw;
    wire op_srlw;
    wire op_sraw;
    assign {op_and, op_or, op_xor, op_add, 
      op_sub, op_slt, op_sltu, op_sll, op_srl, op_sra, op_addw, op_subw, op_sllw, op_srlw, op_sraw} = alu_op;

    wire [63:0] and_result;
    wire [63:0] or_result; 
    wire [63:0] xor_result;
    wire [63:0] add_sub_result;
    wire [63:0] slt_result;
    wire [63:0] sltu_result;
    wire [63:0] sll_result;
    wire [63:0] srl_result;
    wire [63:0] sra_result;
    wire [31:0] addw_subw_result;
    wire [31:0] sllw_result;
    wire [31:0] srlw_result;
    wire [31:0] sraw_result;
    
    
    wire [63:0] adder_a;
    wire [63:0] adder_b;
    wire        adder_cin;
    wire [63:0] adder_result;
    wire        adder_cout;

    wire [31:0] adder_a_w;
    wire [31:0] adder_b_w;
    wire        adder_cin_w;
    wire [31:0] adder_result_w;
    wire        adder_cout_w;

    
    // we use complement to compute add and sub
    // when sub, we make the src2 negation, and set the cin 1
    // so (src1 - src2) -> (src1 + ~src2 + 1) -> (src1 + (-src2))
    assign adder_a = alu_src1;
    assign adder_b = (op_sub | op_slt | op_sltu) ? ~alu_src2 : alu_src2;
    assign adder_cin = (op_sub | op_slt | op_sltu) ? 1'b1 : 1'b0;
    assign {adder_cout, adder_result} = adder_a + adder_b + adder_cin;

    // the rv64i in addition to rv32i (the operation is 32 bits)
    assign adder_a_w = alu_src1[31:0];
    assign adder_b_w = (op_subw) ? ~alu_src2[31:0] : alu_src2[31:0];
    assign adder_cin_w = (op_subw) ? 1'b1 : 1'b0;
    assign {adder_cout_w, adder_result_w} = adder_a_w + adder_b_w + adder_cin_w;

    assign and_result = alu_src1 & alu_src2;
    assign or_result = alu_src1 | alu_src2;
    assign xor_result = alu_src1 ^ alu_src2;
    assign add_sub_result = adder_result;
    assign addw_subw_result = adder_result_w;

    assign slt_result[63:1] = 63'b0;
    assign slt_result[0] = (alu_src1[63] & ~alu_src2[63]) 
                         | (~(alu_src1[63]^alu_src2[63]) & adder_result[63]);
    
    assign sltu_result[63:1] = 63'b0;
    assign sltu_result[0] = ~adder_cout;

    assign sll_result = alu_src1 << alu_src2[5:0];
    assign srl_result = alu_src1 >> alu_src2[5:0];
    assign sra_result = ($signed(alu_src1)) >>> alu_src2[5:0];

    // the rv64i in addition to rv32i (the operation is 32 bits)
    assign sllw_result = alu_src1 << alu_src2[4:0];
    assign srlw_result = alu_src1[31:0] >> alu_src2[4:0];
    assign sraw_result = ($signed(alu_src1[31:0])) >>> alu_src2[4:0];

    // for 32 bits, we should snext it to 64 bits
    assign alu_result = ({64{op_and}}             & and_result) 
                      | ({64{op_or}}              & or_result)
                      | ({64{op_xor}}             & xor_result) 
                      | ({64{op_add|op_sub  }}    & add_sub_result)
                      | ({64{op_slt         }} & slt_result)
                      | ({64{op_sltu        }} & sltu_result)
                      | ({64{op_sll         }} & sll_result)
                      | ({64{op_srl         }} & srl_result)
                      | ({64{op_sra         }} & sra_result)
                      | ({64{op_addw|op_subw}} & {{32{addw_subw_result[31]}}, addw_subw_result})
                      | ({64{op_sllw        }} & {{32{sllw_result[31]}}, sllw_result})
                      | ({64{op_srlw        }} & {{32{srlw_result[31]}}, srlw_result})
                      | ({64{op_sraw        }} & {{32{sraw_result[31]}}, sraw_result});
endmodule
// the branch r? unit, to decide whether or not branch jump
module bru(
    input wire [63:0] pc,
    input wire [7:0] bru_op,
    input wire [63:0] rdata1,
    input wire [63:0] rdata2,
    input wire [63:0] imm,

    output wire br_e,             // control signal, to decide whether or not jump
    output wire [63:0] br_addr,   // the jump address

    // the next address of current pc, may write the reg and return in some time
    // current pc + 4
    output wire [63:0] br_result 
);

    wire inst_beq, inst_bne, inst_blt, inst_bge, inst_bltu, inst_bgeu, inst_jal, inst_jalr;

    //extract the branch inst
    assign {
        inst_jal, inst_jalr, inst_beq, inst_bne,
        inst_blt, inst_bge, inst_bltu, inst_bgeu
    } = bru_op;

    wire rs1_eq_rs2;
    wire rs1_ne_rs2;
    wire rs1_lt_rs2;
    wire rs1_ltu_rs2;
    wire rs1_ge_rs2;
    wire rs1_geu_rs2;

    // equal, not equal, low(signed), low(unsigned), greater and equal(signed)
    // greater and equal(unsigned)
    assign rs1_eq_rs2 = ~rs1_ne_rs2;
    assign rs1_ne_rs2 = |(rdata1 ^ rdata2);
    assign rs1_lt_rs2 = ($signed(rdata1) < $signed(rdata2));
    assign rs1_ltu_rs2 = rdata1 < rdata2;
    assign rs1_ge_rs2 = ~rs1_lt_rs2;
    assign rs1_geu_rs2 = ~rs1_ltu_rs2;

    wire [63:0] pc_plus_imm; 
    wire [63:0] rs_plus_imm;
    assign pc_plus_imm = pc + imm;

    //for jalr, set the least-significant bit to zero;
    assign rs_plus_imm = (rdata1 + imm) & 32'hfffffffe;

    // to determine whether to jump
    assign br_e = inst_beq & rs1_eq_rs2
                | inst_bne & rs1_ne_rs2
                | inst_blt & rs1_lt_rs2
                | inst_bltu & rs1_ltu_rs2
                | inst_bge & rs1_ge_rs2
                | inst_bgeu & rs1_geu_rs2
                | inst_jal
                | inst_jalr;

    assign br_addr = inst_beq | inst_bne | inst_blt | inst_bltu | inst_bge | inst_bgeu | inst_jal ? pc_plus_imm 
                    :inst_jalr ? rs_plus_imm : 64'b0;

    //bru 结果，可能需要写入到相应的寄存器中
    assign br_result = pc + 4'd4;

endmodule
`define StallBus 6
module ctrl(
    input wire rst_n,
    input wire stallreq_id,
    input wire stallreq_ex,
    input wire stallreq_axi,
    output reg [`StallBus-1:0] stall
);

    always @ (*) begin
        if (!rst_n) begin
            stall = `StallBus'b0;
        end
        else if (stallreq_axi) begin
            stall = `StallBus'b111111;
        end
        //id段发生暂停，此时id及之前暂停
        else if (stallreq_id) begin
            stall = `StallBus'b000111;
        end
        else if (stallreq_ex) begin
            stall = `StallBus'b001111;
        end
        else begin
            stall = `StallBus'b0;
        end
    end
endmodule
module decoder_64i (
    input [31:0] inst,
    
    // ex stage
    output wire [1:0] sel_src1,
    output wire sel_src2,
    output wire [4:0] rs1, rs2,
    output wire [63:0] imm,

    // alu part
    output wire [14:0] alu_op,

    // bru part
    output wire [7:0] bru_op,

    // lsu part
    output wire [6:0] lsu_op,

    // csr part
    output wire [9:0] csr_op,
    output wire [1:0] sel_rf_res,

    // wb stage 
    output wire rf_we,
    output wire [4:0] rf_waddr
);
    //defing slices
    wire [6:0] opcode, funct7;
    wire [15:0] opcode_l, funct7_l;
    wire [7:0] opcode_h, funct7_h;
    wire [4:0] rd, shamt5;
    wire [5:0] shamt6;
    wire [2:0] funct3;
    wire [7:0] funct3_d;
    wire [63:0] imm_i, imm_s, imm_b, imm_u, imm_j;

    //define inst
    wire inst_sll, inst_slli, inst_srl, inst_srli, inst_sra, inst_srai;
    wire inst_add, inst_addi, inst_sub, inst_lui, inst_auipc;
    wire inst_xor, inst_xori, inst_or, inst_ori, inst_and, inst_andi;
    wire inst_slt, inst_slti, inst_sltu, inst_sltiu;
    wire inst_beq, inst_bne, inst_blt, inst_bge, inst_bltu, inst_bgeu;
    wire inst_jal, inst_jalr, inst_fence, inst_fence_i, inst_ecall, inst_ebreak;
    wire inst_csrrw, inst_csrrs, inst_csrrc, inst_csrrwi, inst_csrrsi, inst_csrrci;
    wire inst_lb, inst_lh, inst_lbu, inst_lhu, inst_lw;
    wire inst_sb, inst_sh, inst_sw;
    wire inst_lwu, inst_ld, inst_sd;
    wire inst_addiw, inst_slliw, inst_srliw, inst_sraiw;
    wire inst_addw, inst_subw, inst_sllw, inst_srlw, inst_sraw;

    //define alu operator
    wire op_and;
    wire op_or;
    wire op_xor;
    wire op_add;
    wire op_sub;
    wire op_slt;
    wire op_sltu;
    wire op_sll;
    wire op_srl;
    wire op_sra;
    wire op_addw;
    wire op_subw;
    wire op_sllw;
    wire op_srlw;
    wire op_sraw;


    assign opcode = inst[6:0];
    assign rd = inst[11:7];
    assign funct3 = inst[14:12];
    assign rs1 = inst[19:15];
    assign rs2 = inst[24:20];
    assign shamt5 = inst[24:20];
    assign shamt6 = inst[25:20];
    assign funct7 = inst[31:25]; 

    // sext(imm)
    assign imm_i = {{52{funct7[6]}}, funct7, rs2};
    assign imm_s = {{52{funct7[6]}}, funct7, rd};
    assign imm_b = {{52{funct7[6]}}, rd[0], funct7[5:0], rd[4:1], 1'b0};
    assign imm_u = {{32{inst[31]}}, inst[31:12], 12'b0};
    assign imm_j = {{44{inst[31]}}, inst[19:12], inst[20], inst[30:21], 1'b0};

    decoder_4_16 u0_decoder(
    	.in  (opcode[3:0]  ),
        .out (opcode_l )
    );

    decoder_3_8 u1_decoder(
    	.in  (opcode[6:4]  ),
        .out (opcode_h )
    );
    
    decoder_3_8 u2_decoder(
    	.in  (funct3  ),
        .out (funct3_d)
    );
    
    decoder_4_16 u3_decoder(
    	.in  (funct7[3:0]  ),
        .out (funct7_l )
    );
    
    decoder_3_8 u4_decoder(
    	.in  (funct7[6:4]  ),
        .out (funct7_h )
    );
    

    //decode inst
    assign inst_lui     = opcode_h[3'b011] & opcode_l[4'b0111];
    assign inst_auipc   = opcode_h[3'b001] & opcode_l[4'b0111];
    assign inst_jal     = opcode_h[3'b110] & opcode_l[4'b1111];
    assign inst_jalr    = opcode_h[3'b110] & opcode_l[4'b0111];

    assign inst_beq     = opcode_h[3'b110] & opcode_l[4'b0011] & funct3_d[3'b000];
    assign inst_bne     = opcode_h[3'b110] & opcode_l[4'b0011] & funct3_d[3'b001];
    assign inst_blt     = opcode_h[3'b110] & opcode_l[4'b0011] & funct3_d[3'b100];
    assign inst_bge     = opcode_h[3'b110] & opcode_l[4'b0011] & funct3_d[3'b101];
    assign inst_bltu    = opcode_h[3'b110] & opcode_l[4'b0011] & funct3_d[3'b110];
    assign inst_bgeu    = opcode_h[3'b110] & opcode_l[4'b0011] & funct3_d[3'b111];

    assign inst_lb      = opcode_h[3'b000] & opcode_l[4'b0011] & funct3_d[3'b000];
    assign inst_lh      = opcode_h[3'b000] & opcode_l[4'b0011] & funct3_d[3'b001];
    assign inst_lw      = opcode_h[3'b000] & opcode_l[4'b0011] & funct3_d[3'b010];
    assign inst_ld      = opcode_h[3'b000] & opcode_l[4'b0011] & funct3_d[3'b011];
    assign inst_lbu     = opcode_h[3'b000] & opcode_l[4'b0011] & funct3_d[3'b100];
    assign inst_lhu     = opcode_h[3'b000] & opcode_l[4'b0011] & funct3_d[3'b101];
    assign inst_lwu     = opcode_h[3'b000] & opcode_l[4'b0011] & funct3_d[3'b110];

    assign inst_sb      = opcode_h[3'b010] & opcode_l[4'b0011] & funct3_d[3'b000];
    assign inst_sh      = opcode_h[3'b010] & opcode_l[4'b0011] & funct3_d[3'b001];
    assign inst_sw      = opcode_h[3'b010] & opcode_l[4'b0011] & funct3_d[3'b010];
    assign inst_sd      = opcode_h[3'b010] & opcode_l[4'b0011] & funct3_d[3'b011];

    assign inst_addi    = opcode_h[3'b001] & opcode_l[4'b0011] & funct3_d[3'b000];
    assign inst_slti    = opcode_h[3'b001] & opcode_l[4'b0011] & funct3_d[3'b010];
    assign inst_sltiu   = opcode_h[3'b001] & opcode_l[4'b0011] & funct3_d[3'b011];
    assign inst_xori    = opcode_h[3'b001] & opcode_l[4'b0011] & funct3_d[3'b100];
    assign inst_ori     = opcode_h[3'b001] & opcode_l[4'b0011] & funct3_d[3'b110];
    assign inst_andi    = opcode_h[3'b001] & opcode_l[4'b0011] & funct3_d[3'b111];

    assign inst_slli    = opcode_h[3'b001] & opcode_l[4'b0011] & funct3_d[3'b001] & funct7_h[3'b000] & (~(|inst[28:26]));
    assign inst_srli    = opcode_h[3'b001] & opcode_l[4'b0011] & funct3_d[3'b101] & funct7_h[3'b000] & (~(|inst[28:26]));
    assign inst_srai    = opcode_h[3'b001] & opcode_l[4'b0011] & funct3_d[3'b101] & funct7_h[3'b010] & (~(|inst[28:26]));

    assign inst_addiw   = opcode_h[3'b001] & opcode_l[4'b1011] & funct3_d[3'b000];
    assign inst_slliw   = opcode_h[3'b001] & opcode_l[4'b1011] & funct3_d[3'b001] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_srliw   = opcode_h[3'b001] & opcode_l[4'b1011] & funct3_d[3'b101] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_sraiw   = opcode_h[3'b001] & opcode_l[4'b1011] & funct3_d[3'b101] & funct7_h[3'b010] & funct7_l[4'b0000];

    assign inst_add     = opcode_h[3'b011] & opcode_l[4'b0011] & funct3_d[3'b000] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_sub     = opcode_h[3'b011] & opcode_l[4'b0011] & funct3_d[3'b000] & funct7_h[3'b010] & funct7_l[4'b0000];
    assign inst_sll     = opcode_h[3'b011] & opcode_l[4'b0011] & funct3_d[3'b001] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_slt     = opcode_h[3'b011] & opcode_l[4'b0011] & funct3_d[3'b010] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_sltu    = opcode_h[3'b011] & opcode_l[4'b0011] & funct3_d[3'b011] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_xor     = opcode_h[3'b011] & opcode_l[4'b0011] & funct3_d[3'b100] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_srl     = opcode_h[3'b011] & opcode_l[4'b0011] & funct3_d[3'b101] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_sra     = opcode_h[3'b011] & opcode_l[4'b0011] & funct3_d[3'b101] & funct7_h[3'b010] & funct7_l[4'b0000];
    assign inst_or      = opcode_h[3'b011] & opcode_l[4'b0011] & funct3_d[3'b110] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_and     = opcode_h[3'b011] & opcode_l[4'b0011] & funct3_d[3'b111] & funct7_h[3'b000] & funct7_l[4'b0000];

    assign inst_addw    = opcode_h[3'b011] & opcode_l[4'b1011] & funct3_d[3'b000] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_subw    = opcode_h[3'b011] & opcode_l[4'b1011] & funct3_d[3'b000] & funct7_h[3'b010] & funct7_l[4'b0000];
    assign inst_sllw    = opcode_h[3'b011] & opcode_l[4'b1011] & funct3_d[3'b001] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_srlw    = opcode_h[3'b011] & opcode_l[4'b1011] & funct3_d[3'b101] & funct7_h[3'b000] & funct7_l[4'b0000];
    assign inst_sraw    = opcode_h[3'b011] & opcode_l[4'b1011] & funct3_d[3'b101] & funct7_h[3'b010] & funct7_l[4'b0000];

    assign inst_ecall   = opcode_h[3'b111] & opcode_l[4'b0011] & ~(|inst[31:7]);
    assign inst_ebreak  = opcode_h[3'b111] & opcode_l[4'b0011] & ~(|inst[31:21]) & inst[20] & ~(|inst[19:7]);

    
    //encode alu operator by inst type
    assign op_and = inst_and | inst_andi;
    assign op_or = inst_or | inst_ori;
    assign op_xor = inst_xor | inst_xori;
    assign op_add = inst_add | inst_addi | inst_lui | inst_auipc;
    assign op_sub = inst_sub;
    assign op_slt = inst_slt | inst_slti;
    assign op_sltu = inst_sltu | inst_sltiu;
    assign op_sll = inst_sll | inst_slli;
    assign op_srl = inst_srl | inst_srli;
    assign op_sra = inst_sra | inst_srai;
    assign op_addw = inst_addw | inst_addiw;
    assign op_subw = inst_subw;
    assign op_sllw = inst_sllw | inst_slliw;
    assign op_srlw = inst_srlw | inst_srliw;
    assign op_sraw = inst_sraw | inst_sraiw;

    //encode for access mem
    wire data_ram_en;
    wire data_ram_we;
    wire [3:0] data_size_sel;
    wire data_unsigned;

    //make each operator into a bus, and transfer to other module
    assign alu_op = {
      op_and, op_or, op_xor, op_add, op_sub, op_slt,
      op_sltu, op_sll, op_srl, op_sra, op_addw, op_subw, 
      op_sllw, op_srlw, op_sraw
    };

    assign bru_op = {
        inst_jal, inst_jalr, inst_beq, inst_bne,
        inst_blt, inst_bge, inst_bltu, inst_bgeu
    };

    assign lsu_op = {
        data_ram_en, data_ram_we, data_size_sel, data_unsigned
    };

    assign csr_op = {
        inst_fence, inst_fence_i, inst_ecall, inst_ebreak,
        inst_csrrw, inst_csrrs, inst_csrrc ,inst_csrrwi,
        inst_csrrsi, inst_csrrci
    };

    // pc to src1
    assign sel_src1[0] = inst_auipc;
    // 0   to src1
    assign sel_src1[1] = inst_lui;
    // rs1  to src1 
    // assign sel_src1[2] = 

    // imm to src2
    assign sel_src2 =   inst_lui | inst_auipc | inst_lb | inst_lh | inst_lw | inst_ld | inst_lbu | inst_lhu | inst_lwu |
                        inst_sb | inst_sh | inst_sw | inst_sd | inst_addi | inst_addiw | inst_slti | inst_sltiu | inst_xori | 
                        inst_ori | inst_andi | inst_slli | inst_slliw | inst_srli | inst_srliw | inst_srai | inst_sraiw;
    // rs2 to src2
    // assign sel_src2[1] =

    wire [6:0] sel_imm;
    // I
    assign sel_imm[0] = inst_jalr | inst_lb | inst_lh | inst_lw | inst_ld | inst_lbu | inst_lhu | inst_lwu |
                        inst_addi | inst_addiw | inst_slti | inst_sltiu | inst_xori | inst_ori | inst_andi;
    // S
    assign sel_imm[1] = inst_sb | inst_sh | inst_sw | inst_sd;
    // B
    assign sel_imm[2] = inst_beq | inst_bne | inst_blt | inst_bge | inst_bltu | inst_bgeu;
    // U
    assign sel_imm[3] = inst_lui | inst_auipc;
    // J
    assign sel_imm[4] = inst_jal;
    // shamt5
    assign sel_imm[5] = inst_slliw | inst_srliw | inst_sraiw;
    // shamt6
    assign sel_imm[6] = inst_slli | inst_srli | inst_srai;


    assign imm  = sel_imm[0] ? imm_i 
                : sel_imm[1] ? imm_s
                : sel_imm[2] ? imm_b
                : sel_imm[3] ? imm_u
                : sel_imm[4] ? imm_j 
                : sel_imm[5] ? {59'b0, shamt5} 
                : sel_imm[6] ? {58'b0, shamt6} : 64'b0;

    assign data_ram_en =  inst_lb | inst_lbu | inst_lh | inst_lhu | inst_lw | inst_lwu | inst_ld 
                        | inst_sb | inst_sh | inst_sw | inst_sd;
    assign data_ram_we = inst_sb | inst_sh | inst_sw | inst_sd;

    // byte
    assign data_size_sel[0] = inst_lb | inst_lbu | inst_sb;
    // half word
    assign data_size_sel[1] = inst_lh | inst_lhu | inst_sh;
    // word
    assign data_size_sel[2] = inst_lw | inst_lwu | inst_sw;
    // double word
    assign data_size_sel[3] = inst_ld | inst_sd;
    assign data_unsigned = inst_lbu | inst_lhu | inst_lwu;

    // rf_res from bru
    assign sel_rf_res[0] = inst_jal | inst_jalr;
    // rf_res from lsu
    assign sel_rf_res[1] = inst_lb | inst_lh | inst_lw | inst_ld | inst_lbu | inst_lhu | inst_lwu;
    // rf_res need sext(alu_result[31:0])
    //assign sel_rf_res[2] = inst_addiw | inst_slliw | inst_srliw | inst_sraiw | inst_addw | inst_subw | inst_sllw | inst_srlw | inst_sraw;

    assign rf_we =  inst_lui | inst_auipc | inst_jal | inst_jalr |
                    inst_lb | inst_lh | inst_lw | inst_ld | inst_lbu | inst_lhu | inst_lwu |
                    inst_addi | inst_addiw | inst_slti | inst_sltiu | inst_xori | 
                    inst_ori | inst_andi | inst_slli | inst_slliw | inst_srli | inst_srliw | inst_srai | inst_sraiw |
                    inst_add | inst_addw | inst_sub | inst_subw | inst_sll | inst_sllw | inst_slt | inst_sltu |
                    inst_xor | inst_srl | inst_srlw | inst_sra | inst_sraw | inst_or | inst_and;
                    // inst_fence | inst_fence_i | inst_ecall | inst_ebreak |
                    // inst_csrrw | inst_csrrs | inst_csrrc | inst_csrrwi | inst_csrrsi | inst_csrrci;
    assign rf_waddr = rd;

endmodule
module EX
#(
    parameter ID2EX_WD = 49,
    parameter EX2MEM_WD = 49,
    parameter MEM2EX_WD = 50,
    parameter WB2EX_WD = 50
)(
    input wire clk,
    input wire rst_n,
    input wire [5:0] stall,
    output wire stallreq_ex,

    input wire [ID2EX_WD-1:0] id2ex_bus,
    input wire [MEM2EX_WD-1:0] mem2ex_fwd,
    input wire [WB2EX_WD-1:0] wb2ex_fwd,
    output wire [EX2MEM_WD-1:0] ex2mem_bus,

    output wire [64:0] br_bus,

    output wire data_sram_en,
    output wire [7:0] data_sram_we,
    output wire [63:0] data_sram_addr,
    output wire [63:0] data_sram_wdata
);

    reg [ID2EX_WD-1:0] id2ex_bus_r;
    always @ (posedge clk) begin
        if (!rst_n) begin
            id2ex_bus_r <= 0;
        end
        //nop, id stall and ex not stall
        else if (stall[2]&(!stall[3])) begin
            id2ex_bus_r <= 0;
        end
        //nop, id stall and br_bus[64] ? 
        else if (!stall[2]&br_bus[64]) begin
            id2ex_bus_r <= 0;
        end
        // id not stall so can go on
        else if (!stall[2]) begin
            id2ex_bus_r <= id2ex_bus;
        end
    end

    wire [1:0] sel_src1;
    wire sel_src2;
    wire [4:0] rs1, rs2;
    wire [63:0] rdata1, rdata2;
    wire [63:0] imm;
    wire [14:0] alu_op;
    wire [7:0] bru_op;
    wire [6:0] lsu_op;
    wire [1:0] sel_rf_res;
    wire rf_we;
    wire [4:0] rf_waddr;
    wire [63:0] pc;
    wire [31:0] inst;
    wire [9:0] csr_op;

    assign {
        sel_src1,       //2
        sel_src2,       //1
        rs1,            //5
        rs2,            //5
        rdata1,         //64
        rdata2,         //64
        imm,            //64
        alu_op,         //15
        bru_op,         //8
        lsu_op,         //7
        sel_rf_res,     //2
        rf_we,          //1
        rf_waddr,       //5
        pc,             //64
        inst            //32
    } = id2ex_bus_r;

    wire [63:0] src1, src2;
    wire [63:0] alu_src1, alu_src2;
    wire mem_rf_we, wb_rf_we;
    wire [4:0] mem_rf_waddr, wb_rf_waddr;
    wire [63:0] mem_rf_wdata, wb_rf_wdata;
    assign {mem_rf_we, mem_rf_waddr, mem_rf_wdata} = mem2ex_fwd;
    assign {wb_rf_we, wb_rf_waddr, wb_rf_wdata} = wb2ex_fwd;
    assign src1 = mem_rf_we & (mem_rf_waddr==rs1) & (|rs1) ? mem_rf_wdata
                : wb_rf_we & (wb_rf_waddr==rs1) & (|rs1) ? wb_rf_wdata 
                : rdata1;
    assign src2 = mem_rf_we & (mem_rf_waddr==rs2) & (|rs2) ? mem_rf_wdata
                : wb_rf_we & (wb_rf_waddr==rs2) & (|rs2) ? wb_rf_wdata
                : rdata2;

    assign alu_src1 = sel_src1[0] ? pc
                    : sel_src1[1] ? 64'b0
                    : src1;
    assign alu_src2 = sel_src2 ? imm 
                    : src2;

    wire [63:0] alu_result;
    alu u_alu(
    	.alu_op     (alu_op     ),
        .alu_src1   (alu_src1   ),
        .alu_src2   (alu_src2   ),
        .alu_result (alu_result )
    );
    
    wire br_e;
    wire [63:0] br_addr;
    wire [63:0] br_result;
    bru u_bru(
    	.pc        (pc        ),
        .bru_op    (bru_op    ),
        .rdata1    (src1      ),
        .rdata2    (src2      ),
        .imm       (imm       ),
        .br_e      (br_e      ),
        .br_addr   (br_addr   ),
        .br_result (br_result )
    );
    assign br_bus = {br_e,br_addr};

    wire [7:0] data_ram_sel;
    lsu u_lsu(
    	.lsu_op          (lsu_op          ),
        .rdata1          (src1            ),
        .rdata2          (src2            ),
        .imm             (imm             ),
        .data_sram_en    (data_sram_en    ),
        .data_sram_we    (data_sram_we    ),
        .data_sram_addr  (data_sram_addr ),
        .data_sram_wdata (data_sram_wdata ),
        .data_ram_sel    (data_ram_sel    )
    );

    wire [63:0] ex_result;

    assign ex_result    = sel_rf_res[0] ? br_result 
                        : alu_result;
    
    assign ex2mem_bus = {
        lsu_op,
        data_ram_sel,
        sel_rf_res[1],
        rf_we,
        rf_waddr,
        ex_result,
        pc,
        inst
    };

    assign stallreq_ex = 1'b0;
endmodule
module ID
#(
    parameter ID2EX_WD = 49,
    parameter WB2RF_WD = 50) (
    input wire clk,
    input wire rst_n,
    input wire [5:0] stall,
    input wire br_e,
    //when id stallreq
    //ex is load and data 相关
    output wire stallreq_id,

    input wire pc_valid,
    input wire [63:0] pc,
    input wire [63:0] inst_sram_rdata,

    input wire [WB2RF_WD-1:0] wb2rf_bus,
    output wire [ID2EX_WD-1:0] id2ex_bus
);

    reg pc_valid_r;
    reg [63:0] pc_r;

    wire [1:0] sel_src1;
    wire sel_src2;
    wire [1:0] sel_rf_res;
    wire [14:0] alu_op;
    wire [7:0] bru_op;
    wire [6:0] lsu_op;
    wire [9:0] csr_op;
    wire rf_we;

    wire [4:0] rs1, rs2;
    wire [63:0] rdata1, rdata2;
    wire [63:0] imm;
    wire [4:0] rf_waddr;

    always @ (posedge clk)begin
        if (!rst_n) begin
            pc_valid_r <= 1'b0;
            pc_r <= 64'b0;
        end
        //nop, if stall and id not stall
        else if (stall[1]&(!stall[2]))begin
            pc_valid_r <= 1'b0;
            pc_r <= 64'b0;
        end
        //nop, if not stall and br
        else if (!stall[1]&br_e) begin
            pc_valid_r <= 1'b0;
            pc_r <= 64'b0;
        end
        // if not stall so go on
        else if (!stall[1]) begin
            pc_valid_r <= pc_valid;
            pc_r <= pc;
        end
    end

    reg [63:0] inst_r;
    reg stall_flag;

    always @ (posedge clk) begin
        if (!rst_n) begin
            inst_r <= 64'b0;
            stall_flag <= 1'b0;
        end
        //if not stall, get inst from inst_sram
        else if (!stall[1]) begin
            inst_r <= inst_sram_rdata;
            stall_flag <= 1'b0;
        end
        else if (stall_flag) begin
            
        end
        //if stall and id stall, get inst from inst_ram ? 
        else if (stall[1]&stall[2]) begin
            inst_r <= inst_sram_rdata;
            stall_flag <= 1'b1;
        end
    end

    wire [31:0] inst;
    wire [63:0] inst_tmp;

    assign inst_tmp = stall_flag ? inst_r : inst_sram_rdata;
    assign inst = pc_r[2] ? inst_tmp[63:32] : inst_tmp[31:0];

    decoder_64i u_decoder_64i(
      .inst       (inst       ),
      .sel_src1   (sel_src1   ),
      .sel_src2   (sel_src2   ),
      .rs1        (rs1        ),
      .rs2        (rs2        ),
      .imm        (imm        ),
      .alu_op     (alu_op     ),
      .bru_op     (bru_op     ),
      .lsu_op     (lsu_op     ),
      .csr_op     (csr_op     ),
      .sel_rf_res (sel_rf_res ),
      .rf_we      (rf_we      ),
      .rf_waddr   (rf_waddr   )
    );

    wire wb_rf_we;
    wire [4:0] wb_rf_waddr;
    wire [63:0] wb_rf_wdata;
    assign {wb_rf_we,wb_rf_waddr,wb_rf_wdata} = wb2rf_bus;

    regfile u_regfile(
    	.clk    (clk    ),
        .rst_n  (rst_n  ),
        .rs1    (rs1    ),
        .rdata1 (rdata1 ),
        .rs2    (rs2    ),
        .rdata2 (rdata2 ),
        .we     (wb_rf_we     ),
        .waddr  (wb_rf_waddr  ),
        .wdata  (wb_rf_wdata  )
    );

    assign id2ex_bus = {
        sel_src1,                     //2
        sel_src2,                     //1
        rs1,                          //5
        rs2,                          //5
        rdata1,                       //64
        rdata2,                       //64
        imm,                          //64
        alu_op,                       //15
        bru_op & {8{pc_valid_r}},     //8
        lsu_op & {7{pc_valid_r}},     //7
        sel_rf_res,                   //2
        rf_we & pc_valid_r,           //1
        rf_waddr & {5{pc_valid_r}},   //5
        pc_r,                         //64
        inst & {32{pc_valid_r}}       //32
    };

    //通过时钟，在下一个状态获取，但是放在了ID段（好离谱
    reg [6:0] ex_load_buffer;

    always @ (posedge clk) begin
        if (!rst_n) begin
            ex_load_buffer <= 7'b0;
        end
        else if (stall[2]&(!stall[3])) begin
            ex_load_buffer <= 7'b0;
        end
        else if (!stall[2]) begin
            ex_load_buffer <= {sel_rf_res[1],rf_we,rf_waddr};
        end
    end

    wire ex_is_load;
    wire ex_rf_we;
    wire [4:0] ex_rf_waddr;
    assign {ex_is_load,ex_rf_we,ex_rf_waddr} = ex_load_buffer;
    //ex段为load指令，且发生数据相关时，id段需要被暂停
    wire stallreq_load;
    assign stallreq_load = ex_is_load & ex_rf_we & ((ex_rf_waddr==rs1 & rs1!=0)|(ex_rf_waddr==rs2 & rs2!=0));
    assign stallreq_id = stallreq_load;
    
endmodule
module IF(
    input wire clk,
    input wire rst_n,
    input wire [5:0] stall,

    input wire [64:0] br_bus,

    output wire inst_sram_en,
    output wire [7:0] inst_sram_we,
    output wire [63:0] inst_sram_addr,
    output wire [63:0] inst_sram_wdata
);
    reg pc_valid;
    reg [63:0] pc;
    wire [63:0] pc_nxt;

    wire br_e;
    wire [63:0] br_addr;

    assign {
        br_e, br_addr
    } = br_bus;

    always @ (posedge clk) begin
        if (!rst_n) begin
            pc_valid <= 1'b0;
            pc <= 64'h7fff_fffc;
        end
        else if (!stall[0]) begin
            pc_valid <= 1'b1;
            pc <= pc_nxt;
        end
        /* if (stall[0] & stall[1]) begin  */
        /*   pc_valid <= 1'b0; */
        /*   pc <= 0; */
        /* end */
    end

    assign pc_nxt = br_e ? br_addr : pc + 4'h4;

    assign inst_sram_en     = br_e ? 1'b0 : pc_valid ;
    assign inst_sram_we     = 8'b0;
    assign inst_sram_addr   = pc;//我认为这里应该访问pc_nxt
    assign inst_sram_wdata  = 64'b0;


endmodule
module lsu(
    input wire [6:0] lsu_op,
    input wire [63:0] rdata1,
    input wire [63:0] rdata2,
    input wire [63:0] imm,

    output wire data_sram_en,
    output wire [7:0] data_sram_we,
    output wire [63:0] data_sram_addr,
    output wire [63:0] data_sram_wdata,

    output wire [7:0] data_ram_sel
);

    wire data_ram_en;
    wire data_ram_we;
    // {double word, word, half word, byte}
    wire [3:0] data_size_sel;
    wire data_unsigned;

    wire [7:0] byte_sel;

assign {
        data_ram_en, data_ram_we, data_size_sel, data_unsigned
    } = lsu_op;
    
    // implement addr convert to byte sel
    decoder_3_8 u_decoder_3_8(
    	.in  (data_sram_addr[2:0]  ),
        .out (byte_sel             )
    );
    
    // when byte, select with byte_sel(addr -> byte_sel one hot)
    // when half word, the addr may be 000(0), 010(2), 100(4), 110(6). two hot
    // when word, the addr may be 000(0), 100(4), four hot
    // when double word, the addr may be 000(0), eight hot
    // waring：mismatch between addr and data_size could be exception。
    assign data_ram_sel = data_size_sel[0] ? byte_sel 
                        : data_size_sel[1] ? {{2{byte_sel[6]}},{2{byte_sel[4]}},{2{byte_sel[2]}},{2{byte_sel[0]}}} 
                        : data_size_sel[2] ? {{4{byte_sel[4]}},{4{byte_sel[0]}}}
                        : data_size_sel[3] ? {8{byte_sel[0]}} 
                        : 8'h0;

    assign data_sram_en     = data_ram_en;
    assign data_sram_we    = {8{data_ram_we}} & data_ram_sel;
    assign data_sram_addr   = rdata1 + imm;
    // a trick, copy the data and select with enable
    assign data_sram_wdata  = data_size_sel[0] ? {8{rdata2[7:0]}} 
                            : data_size_sel[1] ? {4{rdata2[15:0]}} 
                            : data_size_sel[2] ? {2{rdata2[31:0]}} 
                            : data_size_sel[3] ? rdata2 : 64'b0;


endmodule
module MEM 
#(
    parameter EX2MEM_WD = 50,
    parameter MEM2WB_WD = 50,
    parameter MEM2EX_WD = 50
)(
    input wire clk,
    input wire rst_n,
    input wire [5:0] stall,
    input wire [EX2MEM_WD-1:0] ex2mem_bus,
    output wire [MEM2WB_WD-1:0] mem2wb_bus,
    output wire [MEM2EX_WD-1:0] mem2ex_fwd,

    input wire [63:0] data_sram_rdata
);
    
    reg [EX2MEM_WD-1:0] ex2mem_bus_r;
    always @ (posedge clk) begin
        if (!rst_n) begin
            ex2mem_bus_r <= 0;
        end
        else if (stall[3]&(!stall[4])) begin
            ex2mem_bus_r <= 0;
        end
        else if (!stall[3]) begin
            ex2mem_bus_r <= ex2mem_bus;
        end
    end

    reg [63:0] data_sram_rdata_r;
    reg stall_flag;
    always @ (posedge clk) begin
        if (!rst_n) begin
            data_sram_rdata_r <= 0;
            stall_flag <= 1'b0;
        end
        else if (!stall[3]) begin
            data_sram_rdata_r <= data_sram_rdata;
            stall_flag <= 1'b0;
        end
        else if (stall_flag) begin
            
        end
        else if (stall[3]&stall[4])begin
            data_sram_rdata_r <= data_sram_rdata;
            stall_flag <= 1'b1;
        end
    end
    wire [63:0] data_tmp;
    assign data_tmp = stall_flag ? data_sram_rdata_r : data_sram_rdata;

    wire [6:0] lsu_op;
    wire data_ram_en;
    wire data_ram_we;
    wire [3:0] data_size_sel;
    wire data_unsigned;
    wire [7:0] data_ram_sel;
    wire sel_rf_res;
    wire rf_we;
    wire [4:0] rf_waddr;
    wire [63:0] ex_result;
    wire [63:0] pc;
    wire [31:0] inst;

    assign {
        lsu_op,
        data_ram_sel,
        sel_rf_res,
        rf_we,
        rf_waddr,
        ex_result,
        pc,
        inst
    } = ex2mem_bus_r;

    assign {
        data_ram_en, data_ram_we, data_size_sel, data_unsigned
    } = lsu_op;

    wire [63:0] mem_result;
    wire [63:0] rf_wdata;

    wire [7:0] b_data;
    wire [15:0] h_data;
    wire [31:0] w_data;
    wire [63:0] d_data;

    assign b_data = data_ram_sel[7] ? data_tmp[63:56] :
                    data_ram_sel[6] ? data_tmp[55:48] :
                    data_ram_sel[5] ? data_tmp[47:40] :
                    data_ram_sel[4] ? data_tmp[39:32] :
                    data_ram_sel[3] ? data_tmp[31:24] :
                    data_ram_sel[2] ? data_tmp[23:16] :
                    data_ram_sel[1] ? data_tmp[15: 8] :
                    data_ram_sel[0] ? data_tmp[ 7: 0] : 8'b0;
    assign h_data = data_ram_sel[6] ? data_tmp[63:48] :
                    data_ram_sel[4] ? data_tmp[47:32] :
                    data_ram_sel[2] ? data_tmp[31:16] :
                    data_ram_sel[0] ? data_tmp[15: 0] : 16'b0;
    assign w_data = data_ram_sel[4] ? data_tmp[63:32] : 
                    data_ram_sel[0] ? data_tmp[31: 0] : 32'b0;
    assign d_data = data_tmp;

    assign mem_result = data_size_sel[0] & data_unsigned ? {56'b0,b_data} :
                        data_size_sel[0] ? {{56{b_data[7]}},b_data} :
                        data_size_sel[1] & data_unsigned ? {48'b0,h_data} :
                        data_size_sel[1] ? {{48{h_data[15]}},h_data} :
                        data_size_sel[2] & data_unsigned ? {32'b0,w_data} :
                        data_size_sel[2] ? {{32{w_data[31]}},w_data} :
                        data_size_sel[3] ? d_data : 64'b0;
    
    assign rf_wdata = sel_rf_res ? mem_result : ex_result;

    assign mem2wb_bus = {
        rf_we,
        rf_waddr,
        rf_wdata,
        pc,
        inst
    };

    assign mem2ex_fwd = {
        rf_we,
        rf_waddr,
        ex_result
    };
endmodule
module mycpu_pipeline1
#(
    parameter ID2EX_WD = 50,
    parameter EX2MEM_WD = 50,
    parameter MEM2WB_WD = 50,
    parameter WB2RF_WD = 50,

    parameter MEM2EX_WD = 50,
    parameter WB2EX_WD = 50
)(
    input  wire clk,
    input  wire rst_n,
    input  wire stallreq_axi,

    output wire         inst_sram_en,
    output wire [7:0]   inst_sram_we,
    output wire [63:0]  inst_sram_addr,
    output wire [63:0]  inst_sram_wdata,
    input  wire [63:0]  inst_sram_rdata,

    output wire         data_sram_en,
    output wire [7:0]   data_sram_we,
    output wire [63:0]  data_sram_addr,
    output wire [63:0]  data_sram_wdata,
    input  wire [63:0]  data_sram_rdata,

    output wire [63:0]  debug_wb_pc,
    output wire [7:0]   debug_wb_rf_we,
    output wire [4:0]   debug_wb_rf_wnum,
    output wire [63:0]  debug_wb_rf_wdata
);

    wire [ID2EX_WD-1:0] id2ex_bus;
    wire [EX2MEM_WD-1:0] ex2mem_bus;
    wire [MEM2WB_WD-1:0] mem2wb_bus;
    wire [WB2RF_WD-1:0] wb2rf_bus;
    wire [MEM2EX_WD-1:0] mem2ex_fwd;
    wire [WB2EX_WD-1:0] wb2ex_fwd;
    wire [64:0] br_bus;
    wire stallreq_ex;
    wire stallreq_id;
    wire [5:0] stall;

    IF u_IF(
    	.clk             (clk             ),
        .rst_n           (rst_n           ),
        .stall           (stall           ),
        .br_bus          (br_bus          ),
        .inst_sram_en    (inst_sram_en    ),
        .inst_sram_we    (inst_sram_we    ),
        .inst_sram_addr  (inst_sram_addr  ),
        .inst_sram_wdata (inst_sram_wdata )
    );

    ID 
    #(
        .ID2EX_WD (ID2EX_WD ),
        .WB2RF_WD (WB2RF_WD )
    )
    u_ID(
    	.clk             (clk             ),
        .rst_n           (rst_n           ),
        .stall           (stall           ),
        .br_e            (br_bus[64]      ),
        .stallreq_id     (stallreq_id     ),
        .pc_valid        (inst_sram_en    ),
        .pc              (inst_sram_addr  ),
        .inst_sram_rdata (inst_sram_rdata ),
        .wb2rf_bus       (wb2rf_bus       ),
        .id2ex_bus       (id2ex_bus       )
    );

    EX 
    #(
        .ID2EX_WD  (ID2EX_WD  ),
        .EX2MEM_WD (EX2MEM_WD ),
        .MEM2EX_WD (MEM2EX_WD ),
        .WB2EX_WD  (WB2EX_WD  )
    )
    u_EX(
    	.clk             (clk             ),
        .rst_n           (rst_n           ),
        .stall           (stall           ),
        .stallreq_ex     (stallreq_ex     ),
        .id2ex_bus       (id2ex_bus       ),
        .mem2ex_fwd      (mem2ex_fwd      ),
        .wb2ex_fwd       (wb2ex_fwd       ),
        .ex2mem_bus      (ex2mem_bus      ),
        .br_bus          (br_bus          ),
        .data_sram_en    (data_sram_en    ),
        .data_sram_we    (data_sram_we    ),
        .data_sram_addr  (data_sram_addr  ),
        .data_sram_wdata (data_sram_wdata )
    );
    
    MEM 
    #(
        .EX2MEM_WD (EX2MEM_WD ),
        .MEM2WB_WD (MEM2WB_WD ),
        .MEM2EX_WD (MEM2EX_WD )
    )
    u_MEM(
    	.clk             (clk             ),
        .rst_n           (rst_n           ),
        .stall           (stall           ),
        .ex2mem_bus      (ex2mem_bus      ),
        .mem2wb_bus      (mem2wb_bus      ),
        .mem2ex_fwd      (mem2ex_fwd      ),
        .data_sram_rdata (data_sram_rdata )
    );
    
    WB 
    #(
        .MEM2WB_WD (MEM2WB_WD ),
        .WB2RF_WD  (WB2RF_WD  ),
        .WB2EX_WD  (WB2EX_WD  )
    )
    u_WB(
    	.clk               (clk               ),
        .rst_n             (rst_n             ),
        .stall             (stall             ),
        .mem2wb_bus        (mem2wb_bus        ),
        .wb2rf_bus         (wb2rf_bus         ),
        .wb2ex_fwd         (wb2ex_fwd         ),
        .debug_wb_pc       (debug_wb_pc       ),
        .debug_wb_rf_we    (debug_wb_rf_we    ),
        .debug_wb_rf_wnum  (debug_wb_rf_wnum  ),
        .debug_wb_rf_wdata (debug_wb_rf_wdata )
    );

    ctrl u_ctrl(
    	.rst_n         (rst_n         ),
        .stallreq_id   (stallreq_id   ),
        .stallreq_ex   (stallreq_ex   ),
        .stallreq_axi  (stallreq_axi  ),
        .stall         (stall         )
    );
    
    
    

endmodule
module regfile(
    input wire clk,
    input wire rst_n,
    
    input wire [4:0] rs1,
    output wire [63:0] rdata1,
    input wire [4:0] rs2,
    output wire [63:0] rdata2,

    input wire we,
    input wire [4:0] waddr,
    input wire [63:0] wdata
);
    reg [63:0] rf [31:0];

    always @ (posedge clk) begin
        if (!rst_n) begin
            rf[ 0] <= 64'b0;
            rf[ 1] <= 64'b0;
            rf[ 2] <= 64'b0;
            rf[ 3] <= 64'b0;
            rf[ 4] <= 64'b0;
            rf[ 5] <= 64'b0;
            rf[ 6] <= 64'b0;
            rf[ 7] <= 64'b0;
            rf[ 8] <= 64'b0;
            rf[ 9] <= 64'b0;
            rf[10] <= 64'b0;
            rf[11] <= 64'b0;
            rf[12] <= 64'b0;
            rf[13] <= 64'b0;
            rf[14] <= 64'b0;
            rf[15] <= 64'b0;
            rf[16] <= 64'b0;
            rf[17] <= 64'b0;
            rf[18] <= 64'b0;
            rf[19] <= 64'b0;
            rf[20] <= 64'b0;
            rf[21] <= 64'b0;
            rf[22] <= 64'b0;
            rf[23] <= 64'b0;
            rf[24] <= 64'b0;
            rf[25] <= 64'b0;
            rf[26] <= 64'b0;
            rf[27] <= 64'b0;
            rf[28] <= 64'b0;
            rf[29] <= 64'b0;
            rf[30] <= 64'b0;
            rf[31] <= 64'b0;
        end
        else if (we) begin
            rf[waddr] <= wdata;
        end
    end

    // assign rdata1 = we & (rs1==waddr) ? wdata : |rs1 ? rf[rs1] : 32'b0;
    assign rdata1 = ~(|rs1) ? 64'b0 : we & (rs1==waddr) ? wdata : rf[rs1];
    // assign rdata2 = we & (rs2==waddr) ? wdata : |rs2 ? rf[rs2] : 32'b0;
    assign rdata2 = ~(|rs2) ? 64'b0 : we & (rs2==waddr) ? wdata : rf[rs2];
endmodulemodule WB
#(
    parameter MEM2WB_WD = 50,
    parameter WB2RF_WD = 50,
    parameter WB2EX_WD = 50
)(
    input  wire clk,
    input  wire rst_n,
    input  wire [5:0] stall,

    input  wire [MEM2WB_WD-1:0] mem2wb_bus,
    output wire [WB2RF_WD-1:0] wb2rf_bus,
    output wire [WB2EX_WD-1:0] wb2ex_fwd,

    output wire [63:0]  debug_wb_pc,
    output wire [7:0]   debug_wb_rf_we,
    output wire [4:0]   debug_wb_rf_wnum,
    output wire [63:0]  debug_wb_rf_wdata
);

    reg [MEM2WB_WD-1:0] mem2wb_bus_r;
    always @ (posedge clk) begin
        if (!rst_n) begin
            mem2wb_bus_r <= 0;
        end
        else if (stall[4]&(!stall[5])) begin
            mem2wb_bus_r <= 0;
        end
        else if (!stall[4]) begin
            mem2wb_bus_r <= mem2wb_bus;
        end
    end
    wire rf_we;
    wire [4:0] rf_waddr;
    wire [63:0] rf_wdata;
    wire [63:0] pc;
    wire [31:0] inst;

    assign {
        rf_we,
        rf_waddr,
        rf_wdata,
        pc,
        inst
    } = mem2wb_bus_r;

    assign wb2rf_bus = {
        rf_we,
        rf_waddr,
        rf_wdata
    };

    assign wb2ex_fwd = wb2rf_bus;

    assign debug_wb_pc = pc;
    assign debug_wb_rf_we = {8{rf_we}};
    assign debug_wb_rf_wnum = rf_waddr;
    assign debug_wb_rf_wdata = rf_wdata;
endmodule